package com.mvc.finance.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.stereotype.Service;

import com.mvc.base.service.BaseCompanyManager;
import com.mvc.base.service.CustomerManager;
import com.mvc.business.model.OrderAssociated;
import com.mvc.business.service.OrderAssociatedManager;
import com.mvc.business.service.OrderManager;
import com.mvc.finance.model.BankStatementCharge;
import com.mvc.finance.model.CommercialInvoice;
import com.mvc.finance.model.CommercialInvoiceCharge;
import com.mvc.finance.model.CommercialInvoiceItem;
import com.mvc.finance.model.ExpenseApply;
import com.mvc.finance.model.FinancePrivilege;
import com.mvc.framework.dao.HibernateIdUtils;
import com.mvc.framework.dao.HibernateWebUtils;
import com.mvc.framework.model.Auditable;
import com.mvc.framework.model.CommonAuditableEntity;
import com.mvc.framework.util.FrameworkContextUtils;
import com.mvc.framework.util.PageSearch;

@Service
public class CommercialInvoiceManager extends BaseCompanyManager<CommercialInvoice, Integer> {

	@Autowired
	private CommercialInvoiceItemManager	commercialInvoiceItemManager;

	@Autowired
	private CommercialInvoiceChargeManager	commercialInvoiceChargeManager;

	@Autowired
	private OrderManager	               orderManager;

	@Autowired
	private CustomerManager	               customerManager;

	@Autowired
	private OrderAssociatedManager	       orderAssociatedManager;

	@Autowired
	private FinancePrivilegeManager	       financePrivilegeManager;

	public void save(CommercialInvoice entity) {
		entity.setTotal(getTotal(entity.getObjectId()));
		if (null == entity.getId()) {
			Integer oldOrderId = entity.getObjectId();
			entity.setUserId(FrameworkContextUtils.getCurrentUserId());
			entity.setObjectId(HibernateIdUtils.getUnCacheCustomizeId(getHibernateTemplate().getSessionFactory(), "commercialInvoiceNo"));
			commercialInvoiceItemManager.updateCommercialInvoiceId(oldOrderId, entity.getObjectId());
			entity.setCompanyId(customerManager.getByObjectId(entity.getCustomerId()).getCompanyId());
			orderAssociatedManager.updateAssociated(oldOrderId, entity.getObjectId(), OrderAssociated.TYPE_COMMERCIAL_INVOICE);
		}
		super.save(entity);
	}

	public CommercialInvoice getObject(Integer objectId) {
		CommercialInvoice commercialInvoice = getByObjectId(objectId);
		if (commercialInvoice != null) {
			commercialInvoice.setCustomer(customerManager.getByObjectId(commercialInvoice.getCustomerId()));
			commercialInvoice.setCommercialInvoiceItems(commercialInvoiceItemManager
			        .getCommercialInvoiceItemsByCommercialInvoiceId(commercialInvoice.getObjectId()));
			commercialInvoice.setCommercialInvoiceCharges(commercialInvoiceChargeManager.getCommercialInvoiceChargesByCommercialInvoiceId(
			        objectId, null));
			commercialInvoice.setCompany(companyManager.getByObjectId(commercialInvoice.getCompanyId()));
		}
		return commercialInvoice;
	}

	protected Double getTotal(Integer commercialInvoiceId) {
		Double total = 0D;
		if (commercialInvoiceId != null) {
			List<CommercialInvoiceItem> orderItems = commercialInvoiceItemManager
			        .getCommercialInvoiceItemsByCommercialInvoiceId(commercialInvoiceId);
			for (CommercialInvoiceItem orderItem : orderItems) {
				total += (orderItem.getQuantity() * orderItem.getUnitPrice());
			}
			List<CommercialInvoiceCharge> statementCharges = commercialInvoiceChargeManager
			        .getCommercialInvoiceChargesByCommercialInvoiceId(commercialInvoiceId, null);
			for (CommercialInvoiceCharge charge : statementCharges) {
				if (charge.getType() == BankStatementCharge.TYPE_FEE) {
					total += charge.getCharge();
				} else if (charge.getType() == BankStatementCharge.TYPE_DEBIT) {
					total -= charge.getCharge();
				}
			}
		}
		return total;
	}

	public void find(final PageSearch page, final Integer userId) {
		getHibernateTemplate().execute(new HibernateCallback<PageSearch>() {
			public PageSearch doInHibernate(Session session) {
				Criteria criteria = HibernateWebUtils.createCriteria(session, page.getEntityClass(), page.getFilters());
				if (userId != null) {
					criteria.add(Restrictions.sqlRestriction("customer_Id in (select B.object_id from B_CUSTOMER B" + " where B.user_id = "
					        + userId + " and rec_status = 1)"));
				}
				if (0 == page.getTotalCount()) {
					criteria.setProjection(Projections.rowCount());
					Object object = criteria.uniqueResult();
					int total = object == null ? 0 : ((Number) object).intValue();
					page.setTotalCount(total);
				}
				addOrder(page, criteria);
				criteria.setProjection(null);
				List<CommercialInvoice> items = criteria.setFirstResult(page.getBegin()).setMaxResults(page.getPageSize()).list();
				for (CommercialInvoice commercialInvoice : items) {
					commercialInvoice.setOrderIds(orderAssociatedManager.getCommercialInvoiceOrderStr(commercialInvoice.getObjectId()));
				}
				page.setList(items);
				return page;
			}
		});
	}

	public List<CommercialInvoice> getPaid() {
		String companyId = financePrivilegeManager.getCompanyIdsByUserId(FrameworkContextUtils.getCurrentUserId(),
		        FinancePrivilege.TYPE_RECEIVEABLE);
		String sql = "select A from " + CommercialInvoice.class.getName() + " A where A.recStatus=? and A.status=?";
		if (companyId == null) {
			return searchBySql(sql, new Object[] { CommonAuditableEntity.REC_STATUS_VALID, ExpenseApply.STATUS_PAYED });
		} else if (companyId.length() > 0) {
			sql += " and companyId in(" + companyId + ")";
			return searchBySql(sql, new Object[] { CommonAuditableEntity.REC_STATUS_VALID, ExpenseApply.STATUS_PAYED });
		} else {
			return new ArrayList<CommercialInvoice>();
		}
	}

	public List<CommercialInvoice> getUnPay() {
		String companyId = financePrivilegeManager.getCompanyIdsByUserId(FrameworkContextUtils.getCurrentUserId(),
		        FinancePrivilege.TYPE_RECEIVEABLE);
		String sql = "select A from " + CommercialInvoice.class.getName() + " A where A.recStatus=? and A.status!=?";
		if (companyId == null) {
			return searchBySql(sql, new Object[] { CommonAuditableEntity.REC_STATUS_VALID, ExpenseApply.STATUS_PAYED });
		} else if (companyId.length() > 0) {
			sql += " and companyId in(" + companyId + ")";
			return searchBySql(sql, new Object[] { CommonAuditableEntity.REC_STATUS_VALID, ExpenseApply.STATUS_PAYED });
		} else {
			return new ArrayList<CommercialInvoice>();
		}
	}

	public Long getNeedAuditCount() {
		Session session = getHibernateTemplate().getSessionFactory().openSession();
		Query query = session.createQuery("select count(*) from " + CommercialInvoice.class.getName()
		        + " where recStatus = ? and status= ?");
		query.setParameter(0, Auditable.REC_STATUS_VALID).setParameter(1, ExpenseApply.STATUS_COMMIT);
		List<Object> result = query.list();
		session.close();
		return (Long) result.get(0);
	}

	public List<Object[]> summary(Integer companyId, Date beginDate, Date endDate) {
		Session session = getHibernateTemplate().getSessionFactory().openSession();
		Query query = session.createQuery("select currency,sum(total) from " + CommercialInvoice.class.getName()
		        + " where recStatus = ? and status >=? and companyId=? and shipDate >= ? and shipDate <= ? group by currency");
		query.setParameter(0, Auditable.REC_STATUS_VALID).setParameter(1, ExpenseApply.STATUS_APPROVAED).setParameter(2, companyId)
		        .setParameter(3, beginDate).setParameter(4, endDate);
		List<Object[]> result = query.list();
		session.close();
		return result;
	}

}
